'use strict';

//- 使用ES6语法重写gulpfile.js，具体如下:
//- 正确使用 const 和 let 替换 var
//- 使用模板字符串`${this.data}`
//- 将工具函数等依赖单独分离，并用import导入
//- 对象字面量缩写、箭头函数
import gulp from 'gulp';                            //- 核心库
import config from './gulp.config.js';              //- 使用外部配置文件
import { argv } from 'yargs';                       //- 获取命令行参数
import px2rem from 'postcss-px2rem';
import pngquant from 'imagemin-pngquant';           //- 深度压缩png图片的imagemin插件
const $ = require('gulp-load-plugins')();           //- 模块化管理插件，$ 是一个对象，加载了依赖里的插件
const sync = require('browser-sync').create();      //- 浏览器自动刷新/多端同步调试
const { pipeline } = require('readable-stream');

const _ENV_ = argv.env;                             //- 环境变量
const _PROD_ = (_ENV_ == 'production');             //- 是否生产环境

// ===== 1.清理目录 =====
gulp.task('clean', () =>
    //- read: false 选项可以防止gulp读取档案内容，让它快一些
    //- force: true 对于当前工作目录之外的安全文件和文件夹，只能使用选项force设置为true才能删除
    //- allowEmpty: 是否允许空目录
    gulp.src(config.clean.src, { read: false, allowEmpty: true })
        .pipe($.clean({ force: true}))
)

// ===== 2.js代码合并/压缩/生成版本号 =====
gulp.task('scripts', () =>
    pipeline(
        gulp.src(config.js.src),
        $.plumber({errorHandler: $.notify.onError('Error: <%= error.message %>')}),
        //- 构建一个可配置的上下文供我们在构建时使用
        $.preprocess({
            context: {
                NODE_ENV: _ENV_ || 'development'
            }
        }),
        // $.sourcemaps.init())
        $.concat(config.js.name),             //- 合并js文件
        // $.sourcemaps.write())
        // gulp.dest(config.js.dest))         //- 输出一个未压缩过的版本
        $.if(_PROD_, $.stripDebug()),         //- 清除console、alert、debugger代码 - 生产模式
        $.babel(),                            //- ES6转ES5
        $.if(_PROD_, $.uglify({
            mangle: true
        }).on('error', (e)=> {
            console.error(e);
        })),                                  //- js压缩
        $.rename({suffix: '.min'}),           //- 重命名文件名，添加.min后缀
        $.if(_PROD_, $.rev()),                //- 给静态资源文件名添加hash值
        gulp.dest(config.js.dest),            //- 输出文件到指定目录
        $.if(_PROD_, $.rev.manifest()),       //- 生成manifest.json 保存源文件名与带版本号的文件名的映射
        $.if(_PROD_, gulp.dest(config.js.rev)),//- 将 rev-manifest.json 输出到 rev 目录内
        sync.reload({stream: true})
    )
);

// ===== 3.编译less/自动添加css前缀/压缩/生成版本号 =====

//- gulp-clean-css 配置项（https://github.com/jakubpawlowicz/clean-css）
const CLEAN_CSS_OPTION = {
    advanced: true,            //- 是否开启高级优化（合并选择器等），默认true
    compatibility: 'ie8',      //- IE8兼容模式 ['ie7'：IE7兼容模式，'ie8'：IE8兼容模式，'*'：IE9+兼容模式]
    keepBreaks: false,         //- [是否保留换行] 默认：false
    keepSpecialComments: '*'   //- [保留所有特殊前缀]
}

const rem_processors = [
    px2rem({
        remUnit: 50
    })
];

gulp.task('less:core', () =>
    pipeline(
        gulp.src(config.less.core.src),
        // 当编译less时出现语法错误或者其他异常时，
        // 会终止watch事件，通常需要查看命令提示符窗口才能知道，
        // 所以我们需要处理出现异常并不终止watch事件（gulp-plumber），并提示我们出现了错误（gulp-notify）
        $.plumber({errorHandler: $.notify.onError('Error: <%= error.message %>')}),
        $.less(),                             //- 编译less文件
        $.autoprefixer(config.browsers),
        $.postcss(rem_processors),
        $.rename({suffix: '.min'}),           //- 重命名文件名，添加.min后缀
        $.if(_PROD_, $.cleanCss(CLEAN_CSS_OPTION, function(details) {
            console.log(details.name + ' originalSize: ' + details.stats.originalSize);
            console.log(details.name + ' minifiedSize: ' + details.stats.minifiedSize);
        })),    //- css压缩
        $.if(_PROD_, $.rev()),
        gulp.dest(config.less.core.dest),     //- 输出文件到指定目录
        $.if(_PROD_, $.rev.manifest()),
        $.if(_PROD_, gulp.dest(config.less.core.rev)),
        sync.reload({stream: true})
    )
);

gulp.task('less:dev', () =>
    pipeline(
        gulp.src(config.less.dev.src),
        $.changed(config.less.dev.dest, {extension:'.css'}),
        $.plumber({errorHandler: $.notify.onError('Error: <%= error.message %>')}),
        $.less(),
        $.autoprefixer(config.browsers),
        $.postcss(rem_processors),
        $.base64({                                  //- BASE64编码图片
            debug: true,
            extensions: ['png', 'jpg'],             //- 限定图片格式
            maxImageSize: 10 * 1024,                //- bytes 限定图片大小 <=10KB
            deleteAfterEncoding: false              //- 在编码之后删除图像
        }),
        $.if(_PROD_, $.cleanCss(CLEAN_CSS_OPTION)),
        gulp.dest(config.less.dev.dest),
        sync.reload({stream: true})
    )
);

// ===== 4.html模块化/js、css静态资源版本号控制 =====
gulp.task('html:dev', () =>
    pipeline(
        gulp.src(config.view.src),
        $.changed(config.view.dest),          //- 过滤未被修改过的文件
        $.ejs({env: _ENV_}),                  //- html模块化
        gulp.dest(config.view.dest),
        sync.reload({stream: true})
    )
);

gulp.task('html:build', () =>
    gulp.src(config.view.src)
        .pipe($.ejs({env: _ENV_}))                  //- html模块化
        .pipe($.htmlmin({
            removeComments: true,                   //- 清除HTML注释
            collapseWhitespace: true,               //- 压缩HTML
            collapseBooleanAttributes: false,       //- 省略布尔属性的值 <input checked="true"/> ==> <input checked />
            removeEmptyAttributes: true,            //- 删除所有空格作属性值 <input id="" /> ==> <input />
            removeScriptTypeAttributes: false,      //- 删除<script>的type="text/javascript"
            removeStyleLinkTypeAttributes: false,   //- 删除<style>和<link>的type="text/css"
            minifyJS: true,                         //- 压缩页面JS
            minifyCSS: true                         //- 压缩页面CSS
        }))
        .pipe($.addSrc(config.rev.json))
        .pipe($.revCollector({
            replaceReved: true                      //- 模板中已经被替换的文件是否还能再被替换
        }))                                         //- 一定要加上这句，不然不会替换掉上一次的值
        .pipe(gulp.dest(config.view.dest))
);

gulp.task('ejs', () =>
    pipeline(
        gulp.src(config.view.src),
        $.ejs({env: _ENV_}),                  //- html模块化
        gulp.dest(config.view.dest),
        sync.reload({stream: true})
    )
);

// ===== 5.图片压缩 =====
gulp.task('image', () =>
    pipeline(
        gulp.src(config.img.src),
        $.if(_PROD_, $.cache(
            $.imagemin([
                $.imagemin.gifsicle({interlaced: true}),    //- 默认：false，隔行扫描gif进行渲染
                $.imagemin.jpegtran({progressive: true}),   //- 默认：false，无损压缩jpg图片
                $.imagemin.optipng({
                    optimizationLevel: 5,                   //- 默认：3，取值范围：0-7（优化等级）
                    use: [pngquant()]                       //- 使用pngquant深度压缩png图片
                }),
                $.imagemin.svgo({
                    plugins: [
                        {removeViewBox: true},
                        {cleanupIDs: false}
                    ]
                })
            ], {
                verbose: true
            })
        )),
        gulp.dest(config.img.dest)
    )
);

// ===== 6.文件拷贝 =====
gulp.task('copy', () =>
    pipeline(
        gulp.src(config.lib.src),
        gulp.dest(config.lib.dest)
    )
);

// ===== 7.css直接内嵌到html文件中 =====
gulp.task('inline', () =>
    pipeline(
        gulp.src(config.view.build),
        $.inlineSource(),
        gulp.dest(config.view.dest)
    )
);

// ===== 8.构建本地开发web服务器 =====
gulp.task('server', () => {
    // BrowserSync [http://www.browsersync.cn/]
    // 让浏览器实时、快速响应文件更改并自动刷新
    // 可以同时在PC、平板、手机等设备下进行调试（多端同步）
    sync.init({
        server: {
            index: config.server.index,
            baseDir: config.server.root
        },
        port: config.server.port
    });

    //- 监听文件变化，执行相应任务
    gulp.watch(config.js.all, gulp.parallel('scripts'));             //- 监听js文件
    gulp.watch(config.less.core.all, gulp.parallel('less:core'));    //- 监听less文件
    gulp.watch(config.less.dev.src, gulp.parallel('less:dev'));      //- 监听css文件
    gulp.watch(config.view.src, gulp.parallel('html:dev'));          //- 监听html文件
    gulp.watch(config.ejs.src, gulp.series("ejs"));                  //- 监听ejs文件
    gulp.watch(config.img.src, gulp.parallel('image'));              //- 监听image文件

    // var watcher = gulp.watch(__dir, [__Task]);
    // watcher.on('change', function (event) {
    //    console.log('Event type: ' + event.type);    //- added, changed, or deleted
    //    console.log('Event path: ' + event.path);    //- The path of the modified file
    // });
});

// ===== 9.实用工具 =====
const getTask = (task) => require('./tasks/' + task)(gulp, $, config);  //- 工具类task提取到外部文件
gulp.task('zip', getTask('zip'));               //- zip压缩备份文件
gulp.task('ftp', getTask('ftp'));               //- ftp代码自动化发布
gulp.task('jshint', getTask('jshint'));         //- js语法检查
gulp.task('sprite', getTask('sprite'));         //- 雪碧图合成
gulp.task('less2sass', getTask('less2sass'));   //- Less转Sass

// ===== 10.代码构建 =====
gulp.task('default',
    gulp.series(
        'clean',
        'scripts',
        gulp.parallel('less:core', 'less:dev'),
        `${_PROD_ ? 'html:build' : 'html:dev'}`,
        'image',
        'copy',
        `${_PROD_ ? 'inline' : 'server'}`
    )
);